package com.join.mybatis.method;

import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.metadata.TableFieldInfo;
import com.baomidou.mybatisplus.core.metadata.TableInfo;
import com.baomidou.mybatisplus.core.metadata.TableInfoHelper;

import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.join.mybatis.annotation.JoinColumn;
import com.join.mybatis.annotation.OneToMany;
import lombok.Getter;
import org.apache.ibatis.builder.MapperBuilderAssistant;
import org.mybatis.logging.Logger;

import java.lang.reflect.Field;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.*;

/**
 * @author chengang
 */
@Getter
public class JoinColumnConfig<T> {

    private MapperBuilderAssistant builderAssistant;

    private Class<T> modelClass;

    private Class fieldClass;

    private String fieldName;

    private String joinColumn;

    private String joinTableClumn;

    private String[] resultColumns;

    private Boolean allConvert=true;

    private TableInfo joinTableInfo;

    private Boolean useJavaType;

    private Boolean lazy;

    public static final Map<Class, Map<String,JoinField>> fieldsMap=new HashMap<>(50);

    public static final Map<Class, Map<String,JoinField>> oneToManyMap=new HashMap<>(50);

    public static final String separato="$_";

    public JoinColumnConfig(MapperBuilderAssistant builderAssistant, Class<T> modelClass) {
        this.modelClass = modelClass;
        this.builderAssistant=builderAssistant;
    }

    //解析
    public void resolve(){
        Field[] fields = modelClass.getDeclaredFields();
        Map fieldMap=new HashMap(1);
        Map fieldOneToManyMap=new HashMap(1);
        for (Field field:fields){
            if(field.isAnnotationPresent(JoinColumn.class)){
                JoinColumn joinClumn = field.getAnnotation(JoinColumn.class);
                if(Objects.nonNull(resultColumns)){
                    allConvert=false;
                }
                this.fieldClass=field.getType();
                TableInfo tableInfo = TableInfoHelper.getTableInfo(field.getType());
                if(Objects.isNull(tableInfo)){
                    tableInfo= TableInfoHelper.initTableInfo(builderAssistant,field.getType());
                }
                this.joinTableInfo=tableInfo;
                this.joinColumn= StrUtil.toUnderlineCase(StringUtils.isBlank(joinClumn.value())?tableInfo.getKeyColumn():joinClumn.value());
                this.resultColumns=underLine(joinClumn.columns());
                this.fieldName=field.getName();
                this.joinTableClumn=StrUtil.toUnderlineCase(joinClumn.joinTableClumn());
                this.useJavaType=joinClumn.useJavaType();
                this.lazy=joinClumn.lazy();
                fieldMap.put(field.getName(),new JoinField(this,JoinColumn.class));
            }
            if(field.isAnnotationPresent(OneToMany.class)){
                OneToMany oneToMany = field.getAnnotation(OneToMany.class);
                if(Objects.nonNull(resultColumns)){
                    allConvert=false;
                }
                Class<?> type = field.getType();
                if(type.equals(List.class)){
                    Type genericType = field.getGenericType();
                    if (genericType instanceof ParameterizedType) {
                        ParameterizedType pt = (ParameterizedType) genericType;
                        // Gets an object of type Class in the generic type
                        Class<?> actualTypeArgument = (Class<?>)pt.getActualTypeArguments()[0];
                        this.fieldClass=actualTypeArgument;
                    }
                }else {
                    throw new RuntimeException("one to many result not list");
                }
                TableInfo tableInfo = TableInfoHelper.getTableInfo(this.fieldClass);
                if(Objects.isNull(tableInfo)){
                    tableInfo= TableInfoHelper.initTableInfo(builderAssistant,this.fieldClass);
                }
                this.joinTableInfo=tableInfo;
                this.joinColumn= StrUtil.toUnderlineCase(oneToMany.value());
                this.resultColumns=underLine(oneToMany.columns());
                this.fieldName=field.getName();
                this.lazy=oneToMany.lazy();
                fieldOneToManyMap.put(field.getName(),new JoinField(this,OneToMany.class));
            }
        }
       JoinColumnConfig.fieldsMap.put(modelClass,fieldMap);
        JoinColumnConfig.oneToManyMap.put(modelClass,fieldOneToManyMap);
    }

    private String[] underLine(String[] columns){
            if(Objects.isNull(columns)||columns.length<1||StrUtil.isBlank(columns[0])){
                List<TableFieldInfo> fieldList = this.joinTableInfo.getFieldList();
                return fieldList.stream().map(TableFieldInfo::getColumn).toArray(String[]::new);
            }
            return Arrays.stream(columns).map(StrUtil::toUnderlineCase).toArray(String[]::new);

    }
}
